/*
 * Copyright 2022 The Open Islands Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.openislands.oi.rpc.base;

public abstract class ItemExtended extends Extended<ItemExtended.ItemFactory<?>, ItemExtended.Item<?>> {
    @Override
    public final Extended<ItemFactory<?>, Item<?>> put(ItemFactory<?> key, Item<?> value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public final Item<?> get(ItemFactory<?> key) {
        throw new UnsupportedOperationException();
    }

    @Override
    public final Item<?> get(ItemFactory<?> key, Item<?> defaultValue) {
        throw new UnsupportedOperationException();
    }

    public <E> void putItem(ItemFactory<E> itemFactory, Item<E> item) {
        super.put(itemFactory, item);
    }

    public <E> void putItem(ItemFactory<E> itemFactory, E element) {
        this.putItem(itemFactory, itemFactory.create(element));
    }

    @SuppressWarnings("unchecked")
    public <E> Item<E> getItem(ItemFactory<E> itemFactory) {
        return (Item<E>) super.get(itemFactory);
    }

    public <E> E getElement(ItemFactory<E> itemFactory) {
        Item<E> item = this.getItem(itemFactory);
        return item != null ? item.get() : null;
    }

    public <E> E getElement(ItemFactory<E> itemFactory, E defaultValue) {
        E itemValue = this.getElement(itemFactory);
        return itemValue != null ? itemValue : defaultValue;
    }

    public static class Item<E> {
        private E element;

        private Item(E element) {
            this.element = element;
        }

        public E get() {
            return this.element;
        }

        public void set(E value) {
            this.element = value;
        }
    }

    public static class ItemFactory<E> {
        public static <E> ItemFactory<E> create() {
            return new ItemFactory<>();
        }

        public Item<E> create(E element) {
            return new Item<>(element);
        }
    }
}
